package com.file.parser.socialsecurity;

import com.file.bo.ResponseData;
import com.file.bo.socialsecurity.GuangdongIndividualRecordSheet;
import com.file.bo.socialsecurity.GuangdongInsuranceParticipation;
import com.file.constant.ErrorCode;
import com.file.parser.BasePdfParser;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.SpreadsheetDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.*;

@Slf4j
public class GuangdongSocialSecurityPdfParser extends BasePdfParser {

    public ResponseData<String> parseGuangdongSocialSecurityPdfToJson(String daId, String filePath) {
        log.info("parseGuangdongSocialSecurityPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            if (filePath.contains("cbzm")) {
                GuangdongInsuranceParticipation guangdongInsuranceParticipation = parseGuangdongInsuranceParticipation(filePath);
                json = JsonUtils.convertObjectToJson(guangdongInsuranceParticipation);
            } else if (filePath.contains("qyd")) {
                GuangdongIndividualRecordSheet guangdongIndividualRecordSheet = parseGuangdongIndividualRecordSheet(filePath);
                json = JsonUtils.convertObjectToJson(guangdongIndividualRecordSheet);
            } else {
                log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseGuangdongSocialSecurityPdfToJson failed, new type not supported");
                return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseGuangdongSocialSecurityPdfToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseGuangdongSocialSecurityPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private GuangdongInsuranceParticipation parseGuangdongInsuranceParticipation(String filePath) {
        GuangdongInsuranceParticipation guangdongInsuranceParticipation = parsePdfText(filePath);
        List<List<String>> rowList = parseFileToRowList(filePath);
        parseListToBO(rowList, guangdongInsuranceParticipation);

        return guangdongInsuranceParticipation;
    }

    private GuangdongIndividualRecordSheet parseGuangdongIndividualRecordSheet(String filePath) {
        GuangdongIndividualRecordSheet guangdongIndividualRecordSheet = parseGuangdongIndividualRecordSheetPdfText(filePath);
        List<List<String>> rowList = parseFileToRowList(filePath);
        parseListToBO(rowList, guangdongIndividualRecordSheet);

        return guangdongIndividualRecordSheet;
    }

    private GuangdongIndividualRecordSheet parseGuangdongIndividualRecordSheetPdfText(String filePath) {
        GuangdongIndividualRecordSheet guangdongIndividualRecordSheet = new GuangdongIndividualRecordSheet();
        String pdfText = getPdfTextByStripper2(filePath);
        String recordPeriod = pdfText.substring(pdfText.indexOf("年度社会保险个人权益记录单") + 13, pdfText.indexOf("单位")).trim();
        String unit = pdfText.substring(pdfText.indexOf("单位：") + 3, pdfText.indexOf("姓名")).trim();
        String comment = "";
        if (pdfText.contains("备注:")) {
            comment = pdfText.substring(pdfText.indexOf("备注:") + 3).trim();
        }
        guangdongIndividualRecordSheet.setRecordPeriod(recordPeriod);
        guangdongIndividualRecordSheet.setUnit(unit);
        guangdongIndividualRecordSheet.setComment(comment.replace(System.getProperty("line.separator", "\n"), ""));

        return guangdongIndividualRecordSheet;
    }

    private GuangdongInsuranceParticipation parsePdfText(String filePath) {
        GuangdongInsuranceParticipation guangdongInsuranceParticipation = new GuangdongInsuranceParticipation();
        String pdfText = getPdfTextByStripper(filePath);
        String proofTime = pdfText.substring(pdfText.lastIndexOf("证明时间") + 4).trim();
        guangdongInsuranceParticipation.setProofTime(proofTime);
        return guangdongInsuranceParticipation;
    }

    private void parseListToBO(List<List<String>> rowList, GuangdongInsuranceParticipation guangdongInsuranceParticipation) {
        String sectionName = "";
        List<GuangdongInsuranceParticipation.InsuranceParticipationRecord> insuranceParticipationRecordList = new ArrayList<>();

        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(0), "姓名")) {
                sectionName = "参保人情况";
            } else if (StringUtils.equalsAny(cellList.get(0), "参保险种情况", "参保起止时间")) {
                continue;
            } else if (StringUtils.equals(cellList.get(4), "养老")) {
                sectionName = "参保险种情况";
                continue;
            } else if (StringUtils.equals(cellList.get(0), "截止")) {
                sectionName = "截止";
            }

            switch (sectionName) {//NOSONAR
                case "参保人情况" :
                    guangdongInsuranceParticipation.setName(cellList.get(1));
                    guangdongInsuranceParticipation.setIdNo(cellList.get(3));
                    break;
                case "参保险种情况" :
                    GuangdongInsuranceParticipation.InsuranceParticipationRecord insuranceParticipationRecord = new GuangdongInsuranceParticipation.InsuranceParticipationRecord();
                    insuranceParticipationRecord.setInsuranceParticipationStartAndEndTime(cellList.get(0) + cellList.get(1) + cellList.get(2));
                    if (StringUtils.isBlank(insuranceParticipationRecord.getInsuranceParticipationStartAndEndTime())) {
                        int currentSize = insuranceParticipationRecordList.size();
                        if (currentSize > 0) {
                            insuranceParticipationRecord.setInsuranceParticipationStartAndEndTime(insuranceParticipationRecordList.get(currentSize - 1).getInsuranceParticipationStartAndEndTime());
                        }
                    }
                    insuranceParticipationRecord.setUnit(cellList.get(3));
                    insuranceParticipationRecord.setInsuredPension(cellList.get(4));
                    insuranceParticipationRecord.setInsuredWorkRelatedInjury(cellList.get(5));
                    insuranceParticipationRecord.setInsuredUnemployment(cellList.get(6));
                    insuranceParticipationRecordList.add(insuranceParticipationRecord);
                    break;
                case "截止" :
                    GuangdongInsuranceParticipation.InsuranceParticipationRecord insuranceParticipationRecord2 = new GuangdongInsuranceParticipation.InsuranceParticipationRecord();
                    insuranceParticipationRecord2.setInsuranceParticipationStartAndEndTime(cellList.get(0));
                    insuranceParticipationRecord2.setUnit(cellList.get(1));
                    insuranceParticipationRecord2.setInsuredPension(cellList.get(2));
                    insuranceParticipationRecord2.setInsuredWorkRelatedInjury(cellList.get(3));
                    insuranceParticipationRecord2.setInsuredUnemployment(cellList.get(4));
                    insuranceParticipationRecordList.add(insuranceParticipationRecord2);
                    break;
            }
        }

        guangdongInsuranceParticipation.setInsuranceParticipationRecordList(insuranceParticipationRecordList);
    }

    private void parseListToBO(List<List<String>> rowList, GuangdongIndividualRecordSheet guangdongIndividualRecordSheet) {
        String sectionName = "";
        List<GuangdongIndividualRecordSheet.InsurancePaymentRecord> insurancePaymentRecords = new ArrayList<>();
        Map<String, String> personalAccountRecordMap = new LinkedHashMap<>();

        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(0), "姓名")) {
                sectionName = "姓名";
            } else if (StringUtils.equals(cellList.get(0), "年月")) {
                sectionName = "年月";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(1), "缴费基数")) {
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "当年缴费月数合计")) {
                sectionName = "当年缴费月数合计";
            } else if (StringUtils.equalsAny(cellList.get(0), "截止本年末累计缴费月数")) {
                sectionName = "截止本年末累计缴费月数";
            } else if (StringUtils.equalsAny(cellList.get(0), "参保缴费记录")) {
                continue;
            } else if (StringUtils.equals(cellList.get(0), "个人账户(本金)记录")) {
                sectionName = "个人账户(本金)记录";
                continue;
            }

            switch (sectionName) {//NOSONAR
                case "姓名" :
                    guangdongIndividualRecordSheet.setName(cellList.get(1));
                    guangdongIndividualRecordSheet.setSocialSecurityNumber(cellList.get(3));
                    guangdongIndividualRecordSheet.setPersonalNumber(cellList.get(5));
                    break;
                case "年月" :
                    GuangdongIndividualRecordSheet.InsurancePaymentRecord insurancePaymentRecord
                            = new GuangdongIndividualRecordSheet.InsurancePaymentRecord();
                    GuangdongIndividualRecordSheet.Pension pension = new GuangdongIndividualRecordSheet.Pension();
                    GuangdongIndividualRecordSheet.UnemploymentInsurance unemploymentInsurance
                            = new GuangdongIndividualRecordSheet.UnemploymentInsurance();
                    GuangdongIndividualRecordSheet.InjuryInsurance injuryInsurance
                            = new GuangdongIndividualRecordSheet.InjuryInsurance();
                    insurancePaymentRecord.setYearAndMonth(cellList.get(0));
                    pension.setPaymentBase(cellList.get(1));
                    pension.setUnitPayment(cellList.get(2));
                    pension.setPersonalPayment(cellList.get(3));
                    insurancePaymentRecord.setPension(pension);
                    unemploymentInsurance.setPaymentBase(cellList.get(4));
                    unemploymentInsurance.setUnitPayment(cellList.get(5));
                    unemploymentInsurance.setPersonalPayment(cellList.get(6));
                    insurancePaymentRecord.setUnemploymentInsurance(unemploymentInsurance);
                    injuryInsurance.setPaymentBase(cellList.get(7));
                    injuryInsurance.setUnitPayment(cellList.get(8));
                    insurancePaymentRecord.setInjuryInsurance(injuryInsurance);
                    insurancePaymentRecords.add(insurancePaymentRecord);
                    break;
                case "当年缴费月数合计" :
                    List<String> totalNumberOfMonthsPaidInTheCurrentYear = new ArrayList<>();
                    totalNumberOfMonthsPaidInTheCurrentYear.add(cellList.get(1));
                    totalNumberOfMonthsPaidInTheCurrentYear.add(cellList.get(2));
                    totalNumberOfMonthsPaidInTheCurrentYear.add(cellList.get(3));
                    guangdongIndividualRecordSheet.setTotalNumberOfMonthsPaidInTheCurrentYear(totalNumberOfMonthsPaidInTheCurrentYear);
                    break;
                case "截止本年末累计缴费月数" :
                    List<String> accumulatedPaymentMonthsByTheEndOfTheCurrentYear = new ArrayList<>();
                    accumulatedPaymentMonthsByTheEndOfTheCurrentYear.add(cellList.get(1));
                    accumulatedPaymentMonthsByTheEndOfTheCurrentYear.add(cellList.get(2));
                    accumulatedPaymentMonthsByTheEndOfTheCurrentYear.add(cellList.get(3));
                    guangdongIndividualRecordSheet.setAccumulatedPaymentMonthsByTheEndOfTheCurrentYear(accumulatedPaymentMonthsByTheEndOfTheCurrentYear);
                    break;
                case "个人账户(本金)记录" :
                    personalAccountRecordMap.put(cellList.get(0), cellList.get(1));
                    break;
            }
        }
        guangdongIndividualRecordSheet.setInsurancePaymentRecords(insurancePaymentRecords);
        guangdongIndividualRecordSheet.setPersonalAccountRecordMap(personalAccountRecordMap);
    }

    private List<List<String>> parseFileToRowList(String filePath) {
        // 1. 读取文件
        File pdf = new File(filePath);

        //页面所有table的记录，每一个元素代表下面一条记录cellList
        List<List<String>> rowList = new ArrayList<>();

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            SpreadsheetDetectionAlgorithm detectionAlgorithm = new SpreadsheetDetectionAlgorithm();
            Map<Integer, List<Rectangle>> pageNumber2RectangleListMap = new HashMap<>();//key为页的序号， value为对应的Rectangle的list

            // 4. 获取每页的PageIterator
            PageIterator pageIterator = objectExtractor.extract();

            // 5. 解析每页的Rectangle
            // 如果单页pdf中有多个Rectangle，则解析出来的List<Rectangle>会有多个对象
            while (pageIterator.hasNext()) {
                Page page = pageIterator.next();
                List<Rectangle> rectangleList = detectionAlgorithm.detect(page);
                if (rectangleList.size() > 0) {
                    pageNumber2RectangleListMap.put(page.getPageNumber(), rectangleList);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm extractionAlgorithm = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : pageNumber2RectangleListMap.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());
                Rectangle rectangle = null;

                List<Rectangle> rectangleList = entry.getValue();
                for (Rectangle r : rectangleList) {
                    double rectangleHeight = r.getHeight();
                    if (Double.compare(rectangleHeight, 0) > 0 && Double.compare(r.getWidth(), 0) > 0) {
                        rectangle = r;
                        break;
                    }
                }
                if (rectangle == null) {
                    throw new RuntimeException("rectangle is null.");
                }

                if (entry.getKey() > 1) {
                    rectangle.setTop(rectangle.getTop());
                }
                rectangle.setBottom(rectangle.getBottom() + 50);
                Page area = page.getArea(rectangle);

                // 如果每页有多个表格，解析每一个table
                List<Table> tableList = extractionAlgorithm.extract(area);
                for (Table table : tableList) {
                    for (int i = 0; i < table.getRowCount(); i++) {
                        List<String> cellList = new ArrayList<>();//一条记录，每个单元格占一个元素
                        for (int j = 0; j < table.getColCount(); j++) {
                            cellList.add(table.getCell(i, j).getText(false));
                        }
                        rowList.add(cellList);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return rowList;
    }

    public static void main(String[] args) {
        String filePath = "D:\\data\\file\\socialsecurity\\20240524\\zd4eqec41762431311904796672_dd472a27b0167d307ada8c117f16bd8e_app-gjzwfw-dzsb_origins\\app-gjzwfw-dzsb_cbzm.pdf";
        GuangdongSocialSecurityPdfParser guangdongSocialSecurityPdfParser = new GuangdongSocialSecurityPdfParser();
        ResponseData<String> responseData = guangdongSocialSecurityPdfParser.parseGuangdongSocialSecurityPdfToJson("", filePath);
        System.out.println(responseData.getData());
    }
}
